/*
** pud_alloc.c for pud in mrcellophane/libpud
** 
** Made by solomon hykes
** Login   <torgau@gmail.com>
** 
** Started on  Thu May 19 02:05:32 2005 solomon hykes
** Last update Mon Jul 11 00:18:46 2005 solomon hykes
*/

#include <pud_sys.h>

u_long	pud_mem_alloc(pud_process *p, size_t size, u_long prot, u_long flags)
{
  sys_pud_process	*proc = (sys_pud_process *)p;
  int		args[9];
  unsigned char	code[] = { 0xcd, 0x80 };
  size_t	written_code_len;
  unsigned char	saved_code[sizeof(code)];
  size_t	saved_code_len;
  u_long	orig_pc;
  u_long	orig_stackp;
  u_long	orig_eax;
  pud_event	*event = NULL;
  u_long	result;

  /* Set the stack */
  args[0] = 0;
  args[1] = 0;
  args[2] = size;
  args[3] = prot;
  args[4] = flags;
  args[5] = -1;
  args[6] = 0;
  args[7] = 0;
  //  args[8] = 0; // useless?

  /* Set the stack pointer */
  printf("setting stackp: OLD[%p] -> TEMP[%p]\n", proc->stackp, proc->stackp - sizeof(args)); 
  orig_stackp = proc->stackp;
  if (pud_stackp_set(p, proc->stackp - sizeof(args)) == ret_err)
    return (NULL);
  if (pud_mem_write(p, proc->stackp, (void *)args, sizeof(args)) == -1)
    return (NULL);

  /* Set eax to mmap syscall number */
  orig_eax = proc->regs.r_eax;
  proc->regs.r_eax = 0xc5;
  sys_pud_setregs(proc);

  /* Set the interruption code */
  saved_code_len = pud_mem_read(p, proc->pc, saved_code, sizeof(saved_code));
  if (saved_code_len == -1)
    return (NULL);
  written_code_len = pud_mem_write(p, proc->pc, code, sizeof(code));
  if (written_code_len == -1)
    return (NULL);
  
  /* Do it! */
  printf("Saving old pc: %p\n", proc->pc);
  orig_pc = proc->pc;
  do
    {
      if (event == NULL)
	pud_step(p, 0);
      else
	pud_step(p, event->pass_signal);
      event = pud_next_event(p);
      if (event == NULL)
	{
	  pud_mem_write(p, proc->pc, saved_code, saved_code_len);
	  return (NULL);
	}
      pud_print_event(p, event); // DEBUG
    }
  //  while (proc->pc <= orig_pc);
  while ((proc->status != status_dead) && (proc->pc <= orig_pc));

  printf("Resetting pc: TMP[%p] -> OLD[%p]\n", proc->pc, orig_pc);
  if (pud_pc_set(p, orig_pc) == ret_err)
    return (NULL);

  printf("Putting back erased code to pc:OLD[%p]\n", proc->pc);
  if (pud_mem_write(p, proc->pc, saved_code, saved_code_len) == -1)
    return (NULL);

  /* Get the result */
  result = proc->regs.r_eax;

  proc->regs.r_eax = orig_eax;
  pud_stackp_set(p, orig_stackp);
  
  return (result);
}
